#ifndef __ZDMMRX_C__
#define __ZDMMRX_C__
#include "zd1205.h"
#include "zd1211.h"
#include "zd80211.h"

extern zd_80211Obj_t dot11Obj;
extern struct net_device *g_dev;
extern void zd1205_notify_disjoin_event(struct zd1205_private *macp, u8 *mac);

#if ZDCONF_AP_SUPPORT == 1
void RxPsPoll(Frame_t *rdu)
{
    struct sk_buff *skb ;
    struct zd1205_private *macp = (struct zd1205_private *)netdev_priv(g_dev);
    unsigned long flag;

    int i, popCount = 0;
	U16 aid;
	U8 vapId = 0;
	Hash_t *pHash;
	MacAddr_t *sta;
    BOOLEAN bHashSearchResult;

	
	//PSDEBUG("RxPsPoll");
	
	aid = durId(rdu) & 0x3FFF;
	sta = addr2(rdu);
	if (isGroup(sta))
		return;
		
	if ((aid > MAX_AID) || (aid == 0)){
        for(i=0;i<rdu->HdrLen;i++)
            printk("%02x ", rdu->header[i] & 0xFF);
        for(i=0;i<rdu->bodyLen;i++)
            printk("%02x ", rdu->body[i] & 0xFF);
        printk("\n");
        printk("Send Class3 Error due to invalid AID=%d\n",aid);
		zd_SendClass3ErrorFrame(sta, vapId);
		return;
	}
	else {
        bHashSearchResult = zd_QueryStaTable(&sta->mac[0], (void**)&pHash);
        if(bHashSearchResult  == FALSE)
        {
            printk("Sta's aid is wrong. We can't find Hash with that aid and return\n");
            return;
        }
        if(pHash != sstByAid[aid])
        {
            printk("pHash By Aid != pHash by index\n");
            //return;
        }
        if (pHash->asoc == STATION_STATE_ASOC)
        {
            flag = dot11Obj.EnterCS();
            while(macp->psBuf[pHash->aid])
            {
                popCount ++;
                skb = macp->psBuf[pHash->aid];
                macp->psBuf[pHash->aid] = macp->psBuf[pHash->aid]->next;
                macp->psBufCnt[pHash->aid]--;
                if(macp->psBufCnt[pHash->aid] < 0)
                    printk("!! %s,%d\n",__func__,__LINE__);
                if(macp->psBuf[pHash->aid] == NULL)
                    macp->last_psBuf[pHash->aid] = NULL;
                if(!macp->intraBuf)
                {
                    macp->intraBuf = skb;
                    macp->last_intraBuf = skb;
                }
                else
                {
                    macp->last_intraBuf->next=skb;
                    macp->last_intraBuf = skb;
                }
                skb->next = NULL;
                macp->intraBufCnt++;
                break; // PS POLL sends only 1 packet 
                //dot11Obj.ExitCS(flag);
                //flag = dot11Obj.EnterCS();

            } 
            printk("%d popped data for aid[%d]\n", popCount,pHash->aid );
            dot11Obj.ExitCS(flag);
            defer_kevent(macp, KEVENT_DEV_QUEUE_XMIT);
            //PsPolled(sta, pHash->aid);

        }
        else
        {
            printk("Send Class3 Error due PS POLL, but not asoc\n");
            zd_SendClass3ErrorFrame(sta, vapId);
        }

	}	
}
#endif

BOOLEAN RxMgtMpdu(Signal_t *signal)
{
	StationState sas, sau;
	FrmDesc_t *pfrmDesc;
	Frame_t *rdu;
	U8 FrmType;
	U16 authSeq = 0;
    U8 bHashSearchResult;
	Hash_t *pHash;
    struct zd1205_private *macp = (struct zd1205_private *)netdev_priv(g_dev);


	ZDEBUG("MgtRxMpdu");
	pfrmDesc = signal->frmInfo.frmDesc;
	rdu = pfrmDesc->mpdu;
	FrmType = frmType(rdu);
	ZDEBUG_V("FrmType", FrmType);

	switch (FrmType){
		case ST_PROBE_REQ:
			signal->id = SIG_PROBE;
			signal->block = BLOCK_SYNCH;
			goto rx_indicate;

		case ST_DEAUTH:
			if (isGroup(addr1(rdu)))
				goto rx_release;
			else
            {
                if ((memcmp(&mBssId.mac[0],addr2(rdu),6)==0 && mBssType==INFRASTRUCTURE_BSS))
                {
                    printk(KERN_ERR "Rx Deauth " MACSTR "Reason:%u\n",MAC2STR((U8 *)addr2(rdu)),reason(rdu));
                    signal->id = SIG_DEAUTH;
                    signal->block = BLOCK_AUTH_RSP;
                    goto rx_indicate;
                }
#if ZDCONF_AP_SUPPORT == 1
                else if ((memcmp(&mBssId.mac[0],addr1(rdu),6)==0 && mBssType==AP_BSS))
                {
                    printk("Rx Deauth from station:" MACSTR "\n",MAC2STR((u8*)addr2(rdu)));
                    bHashSearchResult = zd_QueryStaTable((u8*)addr2(rdu), (void**)&pHash);
                    if(bHashSearchResult)
                        zd1205_notify_disjoin_event(macp, pHash->mac);
                    signal->id = SIG_DEAUTH;
                    signal->block = BLOCK_AUTH_RSP;
                    goto rx_indicate;
                }
#endif
                else
                {
#ifdef WPA_DEBUG
                    u8 *pCh=(u8*)addr2(rdu);
                    u8 i;
                                printk(KERN_ERR "Rx Deauth from unknown station:");
                                for (i=0; i<6; i++)
                                {
                                    printk("%02X ",  *pCh++);
                                }
                                printk("\n");
#endif
                                goto rx_release;
                            }
                                
			}
			

		case ST_AUTH:
			if (isGroup(addr1(rdu)))
				goto rx_release;
			else{
				authSeq = authSeqNum(rdu);
				if ((authSeq == 1) || ((authSeq == 3) && wepBit(rdu))){ //Seqence 1 or 3
					signal->id = SIG_AUTH_ODD;
					signal->block = BLOCK_AUTH_RSP;
					goto rx_indicate;
				}
				else if ((authSeq == 2) || (authSeq == 4)){ //Seqence 2 or 4
					signal->id = SIG_AUTH_EVEN;
					signal->block = BLOCK_AUTH_REQ;
					goto rx_indicate;
				}
				else{
					goto rx_release;
				}
			}	
		
		case ST_DISASOC:
			SsInquiry(addr2(rdu), &sas, &sau);
			if ((memcmp(&mBssId.mac[0],addr2(rdu),6)==0 && mBssType==INFRASTRUCTURE_BSS))
			{
            	printk("Rx DeAssoc from" MACSTR " Reason:%u\n",MAC2STR((U8 *)addr2(rdu)), reason(rdu));
			}
			if(sau == STATION_STATE_NOT_AUTH){
				goto class2_err;
			}	
			else{
                if ((memcmp(&mBssId.mac[0],addr1(rdu),6)==0 && mBssType==AP_BSS))
                {
                    bHashSearchResult = zd_QueryStaTable((u8*)addr2(rdu), (void**)&pHash);
                    if(bHashSearchResult)
                        zd1205_notify_disjoin_event(macp, pHash->mac);
                }
				signal->id = SIG_DISASSOC;
				signal->block = BLOCK_ASOC;
				goto rx_indicate;
			}	
			
		case ST_ASOC_REQ:
			SsInquiry(addr2(rdu), &sas, &sau);
			if (sau == STATION_STATE_NOT_AUTH){
				goto class2_err;
			}	
			else {	
				signal->id = SIG_ASSOC;
				signal->block = BLOCK_ASOC;
				goto rx_indicate;
			}
			
		case ST_REASOC_REQ:
			SsInquiry(addr2(rdu), &sas, &sau);
			if (sau == STATION_STATE_NOT_AUTH){
				goto class2_err;
			}	
			else {	
				signal->id = SIG_REASSOC;
				signal->block = BLOCK_ASOC;
				goto rx_indicate;
			}
			
		case ST_BEACON:	
		case ST_PROBE_RSP:
			//if (mBssType == AP_BSS)
		//		goto rx_release;
			
			signal->id = SIQ_PROBE_RSP_BEACON;
			signal->block = BLOCK_SYNCH;
			goto rx_indicate;			
	
		case ST_ASOC_RSP:
			if (mBssType == AP_BSS)
				goto rx_release;
				
			signal->id = SIG_ASSOC_RSP;
			signal->block = BLOCK_ASOC;
			goto rx_indicate;
			
		case ST_REASOC_RSP:
			if (mBssType == AP_BSS)
				goto rx_release;
				
			signal->id = SIG_REASSOC_RSP;
			signal->block = BLOCK_ASOC;
			goto rx_indicate;
			
		default:
			goto rx_release;
	}
		
rx_release:
	ZDEBUG("goto rx_release");
	return FALSE; 

rx_indicate:	
	signal->frmInfo.frmDesc = pfrmDesc;
	sigEnque(pMgtQ, (signal));
	return TRUE;

class2_err:
	ZDEBUG("goto class2_err");
	signal->id =  SIG_DEAUTH_REQ;
	signal->block = BLOCK_AUTH_REQ;
	memcpy((U8 *)&signal->frmInfo.Sta, (U8 *)(addr2(rdu)), 6);
	signal->frmInfo.rCode = RC_CLASS2_ERROR;
	freeFdesc(pfrmDesc);
	sigEnque(pMgtQ, (signal));
	return TRUE;
}

#endif

